﻿function Database(hostName, databaseName, username, password)
{
	var MariaSQLClient = require('mariasql');

	this.systemDatabase = new MariaSQLClient();
	this.systemDatabase.connect
	(
		{
	  		host: hostName,
			db: databaseName,
	  		user: username,
	  		password: password
		}
	);

	this.systemDatabase.on
	(
		"connect", 
		function() { }
		).on
	(
		"error", 
		function(err) { console.log('Clientor: ' + err); }
	).on
	(
		"close", 
		function(hadError) {  }
	);
}
{	
	Database.prototype.query = function
	(
		queryText, 
		entityToReadInto, 
		objectForEvents,
		eventLoaded,
		eventFinished
	)
	{
		this.systemDatabase.query(queryText).on
		(
			"result", 
			function(result) 
			{
				result.on
				(
					"row",
					function(row)
					{					
						entityToReadInto.readFromDatabase_BuildFromRow.call
						(
							entityToReadInto,
							row,
							objectForEvents,
							eventLoaded
						);
					}
				).on
				(
					"error", 
					function(err) 
					{ 
						console.log("Databaser!"); 
					}
				).on
				(
					"end", 
					function(info) 
					{							
						if (eventFinished != null)
						{
							eventFinished.call(objectForEvents);
						}
					}
				);
		 	}
		).on
		(
			'end', 
			function() { }
		);
	}

	Database.prototype.dispose = function()
	{
		this.systemDatabase.end();
	}
}

function HTMLHelper()
{}
{
	HTMLHelper.escape = function(stringToEscape)
	{
		var returnValue = stringToEscape.replace
		(
			"&", "&amp;"
		).replace
		(
			"<", "&lt;"
		).replace
		(
			">", "&gt;"
		);

		return returnValue;
	}

	HTMLHelper.unescape = function(stringToUnescape)
	{
		var returnValue = stringToEscape.replace
		(
			"&amp;", "&"
		).replace
		(
			"&lt;", "<"
		).replace
		(
			"&gt;", ">"
		);

		return returnValue;
	}
}

function NetworkHelper()
{}
{
	NetworkHelper.httpGet = function(urlToGetFrom)
	{
		var request = new XMLHttpRequest();
		request.open("GETlToGetFrom, false);
		request.send(null);
		return request.response;
	}

	NetworkHelper.httpPost = function(urlToPostTo, valueToPost)
	{
		var request = new XMLHttpRequest();
		request.open("POSTlToPostTo, false);
		request.send(valueToPost);
		return request.response;
	}
}

function PersistenceStatus(name)
{
	this.name = name;
}
{
	PersistenceStatus.Instances = new PersistenceStatus_Instances();

	function PersistenceStatus_Instances()
	{
		this.Created = new PersistenceStatus("Created");
		this.Modified = new PersistenceStatus("Modified");
		this.Saved = new PersistenceStatus("Saved");
		this.Unknown = new PersistenceStatus("Unknown");

		this._All = 
		[
			this.Created,
			this.Modified,
			this.Saved,
			this.Unknown,
		];
	}
}

function XMLAttribute(name, value)
{
	this.name = name;
	this.value = value;
}

function XMLElement(parent, tagName, attributes, children)
{
	this.parent = parent;
	this.tagName = tagName;
	this.attributes = attributes;
	this.children = children;
}
{
	XMLElement.parseFromString = function(stringToParse)
	{
		var tagsAsStrings = stringToParse.split("<");

		var elementRoot = new XMLElement
		(
			null, // parent
			null, // tagName
			[], // attributes
			[] // children
		);

		var elementCurrent = elementRoot;

		for (var t = 0; t < tagsAsStrings.length; t++)
		{
			var tagAsString = tagsAsStrings[t];

			if (tagAsString.length == 0)
			{
				// do nothing
			}
			else if (tagAsString.indexOf("/") == 0)
			{
				elementCurrent = elementCurrent.parent;
			}
			else
			{				
				if (tagAsString.lastIndexOf("/>") == tagAsString.length - 2)
				{
					tagAsString = tagAsString.substring(0, tagAsString.length - 2) + " />";
				}
				else if (tagAsString.lastIndexOf(">") == tagAsString.length - 1)
				{
					tagAsString = tagAsString.substring(0, tagAsString.length - 1) + " >";
				}				

				var tokensFromTag = tagAsString.split(" ");

				var tagName = tokensFromTag[0];

				var attributes = [];

				for (var a = 1; a <= tokensFromTag.length - 1; a++)
				{
					var attributeAsString = tokensFromTag[a];

					var indexOfEqualsSign = attributeAsString.indexOf("=");
					if (indexOfEqualsSign >= 0)
					{	
						var attributeName = attributeAsString.substring(0, indexOfEqualsSign);
						var attributeValue = attributeAsString.substring(indexOfEqualsSign + 1);

						if (attributeValue.indexOf("'") == 0)
						{
							while (attributeValue.lastIndexOf("'") != attributeValue.length - 1)
							{
								a++;
								attributeValue += " " + tokensFromTag[a];
							}

							attributeValue = attributeValue.substring
							(
								1, attributeValue.length - 1
							);
						}

						var attribute = new XMLAttribute
						(
							attributeName,
							attributeValue
						);

						attributes.push(attribute);
						attributes[attribute.name] = attribute;
					}
				}

				var elementNew = new XMLElement
				(
					elementCurrent,
					tagName,
					attributes,
					[] // children
				);

				elementCurrent.children.push(elementNew);

				elementCurrent = elementNew;

				if (tagAsString.indexOf("/>") == (tagAsString.length - 2))
				{
					elementCurrent = elementCurrent.parent;
				}
			}
		}

		var returnValue = elementRoot.children[0];

		return returnValue;
	}

	// instance methods

	XMLElement.prototype.toString = function()
	{
		var returnValue = "<" + this.tagName;

		for (var i = 0; i < this.attributes.length; i++)
		{
			var attribute = this.attributes[i];

			returnValue += 
				" " + attribute.name 
				+ "='" + attribute.value + "'"
		}

		if (this.children.length == 0)
		{
			returnValue += "/";	
		}

		returnValue += ">";

		for (var i = 0; i < this.children.length; i++)
		{
			var child = this.children[i];

			returnValue += child.toString();
		}

		return returnValue;
	}
}